<template>
  <div class="event-loop-test padding-box-100" @scroll="scroll">
    <div class="event-loop-test-box">
      滚动屏幕，进行实验：下方内容为输出的日志👇👇👇
      最大日志条数 {{ maxLogStackLength }}
      <button class="event-loop-test-button" style="right: 20px" @click="handleClick">{{
          closeLog ? '关闭' : '打开'
        }}日志输出
      </button>
      <button class="event-loop-test-button" style="right: 130px" @click="clearLog">清空日志</button>
      <div v-for="(item, i) in logStack" :key="i">{{ item }}</div>
    </div>
  </div>
</template>

<script lang="ts">
import {reactive, defineComponent, ref, onBeforeUnmount} from 'vue'

export default defineComponent({
  setup() {

    let count = 1
    const maxLogStackLength = 500
    const closeLog = ref(true)
    let logStack = reactive([])
    let requestAnimationFrameNumber, requestIdleCallbackNumber;

    onBeforeUnmount(() => {
      cancelAnimationFrame(requestAnimationFrameNumber)
      window.cancelIdleCallback(requestIdleCallbackNumber)
    })

    function pushLog(log) {

      if (!closeLog.value) {
        return;
      }

      if (!logStack.length) {
        logStack.push(log)
        return
      }

      // 取出日志的最后一条
      let lastLog = logStack[logStack.length - 1]

      if (lastLog.endsWith(log)) {
        logStack.splice(logStack.length - 1, 1, lastLog.replace(/^\d*/, match => +(match || 0) + 1))
      } else {
        if (logStack.length >= maxLogStackLength) {
          logStack.shift()
        }
        logStack.push(log)
      }

    }

    function log(log) {

      if (!closeLog.value) {
        return;
      }

      pushLog(log)
      console.log(log)
    }

    function onRefresh() {
      requestAnimationFrameNumber = requestAnimationFrame(() => {
        onRefresh()
        log('--------requestAnimationFrame---------')
      })
    }

    function myRequestIdleCallback() {
      requestIdleCallbackNumber = window.requestIdleCallback(() => {
        log('--------requestIdleCallback---------')
        myRequestIdleCallback()
      })
    }

    // 设置 递归进行的 requestAnimationFrame 和 requestIdleCallback
    onRefresh()
    myRequestIdleCallback()

    const resolve = Promise.resolve()


    function scroll() {
      let a = count++

      // scroll 执行日志输出
      log(`---scroll---${a}`)

      // 设置一个 Promise ，在 then 的回调中输出日志
      resolve.then(() => {
        log(`---Promise---${a}`)
      })

      // 在设置 Promise 后，再次输出日志
      log(`---scroll---after---${a}`)

      // 添加两个宏任务
      setTimeout(() => {
        log(`---setTimeout---1---${a}`)
      })

      setTimeout(() => {
        log(`---setTimeout---2---${a}`)
      })

    }

    function handleClick() {
      closeLog.value = !closeLog.value
    }

    function clearLog() {
      logStack.splice(0, logStack.length)
    }

    return {
      scroll,
      closeLog,
      logStack,
      handleClick,
      clearLog,
      maxLogStackLength,
    }
  }
})
</script>

<style scoped>
.event-loop-test {
  height: 100vh;
  overflow: auto;
}

.event-loop-test-box {
  height: 200vh;
}

.event-loop-test-button {
  position: fixed;
  top: 20px;
}
</style>
